package net.hpxn.gsmc.core.server;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import net.hpxn.gsmc.config.server.ServerConfigs.ServerConfig;
import net.hpxn.gsmc.core.server.exceptions.ServerCommunicationException;
import net.hpxn.gsmc.core.server.exceptions.ServerUnavailableException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

public class MinecraftServer extends Server {

	public MinecraftServer( ServerConfig pServerConfig ) {
		super( pServerConfig );
	}

	@Override
	public void updateServerStatus() throws ServerUnavailableException {
		try {
			String wServerStatus = getServerStatus();
			
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			DocumentBuilder db = dbf.newDocumentBuilder();
			Document doc = db.parse( new InputSource(new java.io.StringReader(wServerStatus)) );

			doc.getDocumentElement().normalize();
			NodeList nodeLst = doc.getElementsByTagName( "server" );
			for ( int s = 0; s < nodeLst.getLength(); s++ ) {

				Node fstNode = nodeLst.item( s );

				if ( fstNode.getNodeType() == Node.ELEMENT_NODE ) {

					Element fstElmnt = (Element) fstNode;

					NodeList maxPlayersElmntLst = fstElmnt
							.getElementsByTagName( "maxPlayers" );
					Element maxPlayersElmnt = (Element) maxPlayersElmntLst
							.item( 0 );
					NodeList maxPlayers = maxPlayersElmnt.getChildNodes();
					setMaxPlayers( Integer
							.valueOf( ((Node) maxPlayers.item( 0 ))
									.getNodeValue() ) );

					NodeList numPlayersElmntLst = fstElmnt
							.getElementsByTagName( "numPlayers" );
					Element numPlayersElmnt = (Element) numPlayersElmntLst
							.item( 0 );
					NodeList numPlayers = numPlayersElmnt.getChildNodes();
					setPlayerCount( Integer.valueOf( ((Node) numPlayers
							.item( 0 )).getNodeValue() ) );

					NodeList worldNameElmntLst = fstElmnt
							.getElementsByTagName( "worldName" );
					Element worldNameElmnt = (Element) worldNameElmntLst
							.item( 0 );
					NodeList worldName = worldNameElmnt.getChildNodes();
					setMapName( ((Node) worldName.item( 0 )).getNodeValue() );

					NodeList serverVersionElmntLst = fstElmnt
							.getElementsByTagName( "serverVersion" );
					Element serverVersionElmnt = (Element) serverVersionElmntLst
							.item( 0 );
					NodeList serverVersion = serverVersionElmnt.getChildNodes();
					setVersion( ((Node) serverVersion.item( 0 )).getNodeValue() );
				}
			}

		} catch ( ServerCommunicationException e ) {
			throw new ServerUnavailableException( e );
		} catch ( ParserConfigurationException e ) {
			throw new ServerUnavailableException( e );
		} catch ( SAXException e ) {
			throw new ServerUnavailableException( e );
		} catch ( IOException e ) {
			throw new ServerUnavailableException( e );
		}
	}

	@Override
	protected String getServerStatus() throws ServerCommunicationException {
		return sendRaw( "status" );
	}

	@Override
	public String sendRaw( String pMsg ) throws ServerCommunicationException {
		try {
			Socket socket = new Socket( getRemoteIp(), getRemotePort() );
			try {
				BufferedReader in = new BufferedReader( new InputStreamReader(
						socket.getInputStream() ) );

				PrintWriter out = new PrintWriter( new BufferedWriter(
						new OutputStreamWriter( socket.getOutputStream() ) ),
						true );

				out.println( pMsg );
				return in.readLine();

			} finally {
				socket.close();
			}
		} catch ( IOException e ) {
			throw new ServerCommunicationException( e );
		}
	}
}
